﻿using System;
using System.Collections.Generic;
using System.Text;
using alglib;

namespace Engine.Mathematics
{
    /** Vector implementation. */
    public class Vector : ICloneable
    {
        internal double[] store;

        private int _size;

        public Vector(double[] vectorData)
        {
            _size = vectorData.GetLength(0);
            store = new double[_size];
            Array.Copy(vectorData, store, vectorData.GetLength(0));
        }

        public Vector(int size)
        {
            store = new double[size];
            _size = size;
        }

        public static Vector operator +(Vector a,Vector b)
        {
            if(a.Size != b.Size)
            {
                throw new ArgumentException("First and second matrix must have equal size.");
            }
            Vector c = new Vector(a.Size);
            for (int i = 0; i < a.Size ; i++ )
            {
                c[i] = a[i] + b[i];
            }
            return c;
        }

        public static Vector operator -(Vector a, Vector b)
        {
            if (a.Size != b.Size)
            {
                throw new ArgumentException("First and second matrix must have equal size.");
            }
            Vector c = new Vector(a.Size);
            for (int i = 0; i < a.Size; i++)
            {
                c[i] = a[i] - b[i];
            }
            return c;
        }

        /** scalar product of two vectors. */
        public static double operator *(Vector a, Vector b)
        {
            if (a.Size != b.Size)
            {
                throw new ArgumentException("First and second matrix must have equal size.");
            }
            double summ = 0;
            for (int i = 0; i < a.Size; i++ )
            {
                summ += a[i] * b[i];
            }
            return summ;
        }

        public static Vector operator /(Vector a, double b)
        {
            Vector c = new Vector(a.Size);
            for (int i = 0; i < a.Size; i++ )
            {
                c[i] = a[i] / b;
            }
            return c;
        }

        public static Vector operator *(Vector a, double b)
        {
            Vector c = new Vector(a.Size);
            for (int i = 0; i < a.Size; i++)
            {
                c[i] = a[i] * b;
            }
            return c;
        }

        public double this[int i]
        {
            get { return store[i]; }
            set { store[i] = value; }
        }

        public int Size
        {
            get { return _size; }
        }

        /** calculate norm of this vector */
        public double Norm
        {
            get
            {
                double summ = 0;
                foreach (double v in store)
                {
                    summ += Math.Pow(v, 2d);
                }
                return Math.Sqrt(summ);
            }
        }

        /// <summary>
        /// This norm is calculated as max|xi|
        /// </summary>
        public double Norm2
        {
            get
            {
                double maxValue = double.NegativeInfinity;
                foreach (var value in store)
                {
                    if (value > maxValue) maxValue = value;
                }
                return maxValue;
            }
        }

        public double[] Data 
        {
            get { return store; }
        }

        public void RemoveLastComponent() 
        {
            double[] copy = new double[_size - 1];
            Array.Copy(store, copy, _size - 1);
            this.store = copy;
            _size--;
        }

        #region ICloneable Members

        public object Clone()
        {
            Vector clone = new Vector(store);
            return clone;
        }

        #endregion
    }
}
